package com.baidu.acg.industry.bigdata.utils;

import com.baidu.acg.industry.bigdata.client.MinioClientFactory;
import io.minio.*;
import io.minio.http.Method;
import io.minio.messages.Item;
import lombok.extern.slf4j.Slf4j;
import org.apache.tika.Tika;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.io.InputStream;
import java.nio.file.Path;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

@Slf4j
@Component
public class MinioUtil {

    @Autowired
    private MinioClientFactory minioClient;
    private Tika tika;


    // 上传文件并返回可下载链接（默认有效期7天）
    public String uploadFile(String bucketName, String localFilePath, String objectPath)
            throws Exception {
        ensureBucketExists(bucketName);

        try {
            // 上传文件
            ObjectWriteResponse objectWriteResponse = minioClient.createMinioClient().uploadObject(
                    UploadObjectArgs.builder()
                            .bucket(bucketName)
                            .object(objectPath)
                            .filename(localFilePath)
                            .build());
            String string = objectWriteResponse.toString();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }

        // 返回预签名下载链接
        return generatePresignedUrl(bucketName, objectPath, 7);
    }

    // 上传文件夹并返回文件路径与链接的映射
    public Map<String, String> uploadDirectory(String bucketName, String localDirPath, String prefix)
            throws Exception {
        Map<String, String> urlMap = new HashMap<>();
        Path dirPath = Paths.get(localDirPath);

        Files.walk(dirPath)
                .filter(Files::isRegularFile)
                .forEach(file -> {
                    try {
                        String objectName = buildObjectName(dirPath, file, prefix);
                        String url = uploadFile(bucketName, file.toString(), objectName);
                        urlMap.put(file.toString(), objectName);
                    } catch (Exception e) {
                        log.error("upload fail : " + file + " - " + e.getMessage());
                    }
                });

        return urlMap;
    }

    // 生成预签名下载链接
    public String generatePresignedUrl(String bucketName, String objectPath, int expiryDays)
            throws Exception {
        return minioClient.createMinioClient().getPresignedObjectUrl(
                GetPresignedObjectUrlArgs.builder()
                        .method(Method.GET)
                        .bucket(bucketName)
                        .object(objectPath)
                        .expiry(expiryDays, TimeUnit.DAYS)
                        .build());
    }

    private String buildObjectName(Path root, Path file, String prefix) {
        String relativePath = root.relativize(file).toString().replace("\\", "/");
        return prefix.isEmpty() ? relativePath : prefix + "/" + relativePath;
    }

    private void ensureBucketExists(String bucketName) throws Exception {
        if (!minioClient.createMinioClient().bucketExists(BucketExistsArgs.builder().bucket(bucketName).build())) {
            minioClient.createMinioClient().makeBucket(MakeBucketArgs.builder().bucket(bucketName).build());

        }
    }

    /**
     * 根据 MinIO 文件路径下载文件到本地
     *
     * @param bucketName 存储桶名称
     * @param objectPath MinIO 中的文件路径（如 "documents/report.pdf"）
     * @param localPath  本地保存路径（如 "/downloads/report.pdf"）
     */
    public void downloadFile(String bucketName, String objectPath, String localPath)
            throws Exception {
        // 1. 检查存储桶是否存在
        if (!minioClient.createMinioClient().bucketExists(BucketExistsArgs.builder().bucket(bucketName).build())) {
            throw new IllegalStateException("bucket not exist: " + bucketName);
        }

        // 2. 获取文件流
        try (
                InputStream stream = minioClient.createMinioClient().getObject(
                        GetObjectArgs.builder()
                                .bucket(bucketName)
                                .object(objectPath)
                                .build())) {

            // 3. 确保本地目录存在
            Path savePath = Paths.get(localPath + "/" + objectPath);
            Files.createDirectories(savePath.getParent());

            // 4. 保存到本地
            Files.copy(stream, savePath, StandardCopyOption.REPLACE_EXISTING);
            log.info("file download success: " + localPath);
        }
    }
    /**
     * 把 MinIO 中以某个前缀（“文件夹”）开头的所有对象下载到本地目录。
     *
     * @param bucketName   存储桶
     * @param prefix       对象前缀（如 "documents/reports/"；结尾最好带 /）
     * @param localBaseDir 本地根目录（如 "/downloads"）
     */
    public void downloadDirectory(String bucketName, String prefix, String localBaseDir) throws Exception {
        // 1. 确保桶存在（如不存在会自动创建，保持和 uploadDirectory 的语义一致）
        ensureBucketExists(bucketName);

        // 2. 遍历列举前缀下所有对象（递归）
        Iterable<Result<Item>> results = minioClient.createMinioClient().listObjects(
                ListObjectsArgs.builder()
                        .bucket(bucketName)
                        .prefix(prefix)
                        .recursive(true)           // 递归列出子“文件夹”
                        .build());

        for (Result<Item> result : results) {
            Item item = result.get();

            // 过滤目录占位符或删除标记
            if (item.isDir() || item.isDeleteMarker()) {
                continue;
            }

            String objectName = item.objectName();

            // 3. 计算本地保存路径
            Path localPath = Paths.get(localBaseDir, objectName);
            Files.createDirectories(localPath.getParent());

            // 4. 下载到本地
            try (InputStream in = minioClient.createMinioClient().getObject(
                    GetObjectArgs.builder()
                            .bucket(bucketName)
                            .object(objectName)
                            .build())) {
                Files.copy(in, localPath, StandardCopyOption.REPLACE_EXISTING);
                log.info("Downloaded: {}", localPath);
            }
        }
    }


}